//引入parser模块
const {getAst,getDeps,getCode} = require('./parser')
const fs = require('fs')
const path = require('path')

class compiler{
    constructor(options={}){
        //webpack配置对象
        this.options = options
        //所有依赖的容器
        this.modules = []
    }
    //启动webpack打包
    run(){
        //入口文件路径
        const filePath = this.options.entry;
        //第一次构建，得到入口文件的信息
        const fileInfo = this.build(filePath)
        this.modules.push(fileInfo)
        this.modules.forEach(fileInfo=>{
            //取出当前文件的所有依赖
            const deps = fileInfo.deps
            /**
             * {
                './add.js': 'D:\\前端自学代码库\\webpack-vue\\05.mywebpack\\src\\add.js',
                './count.js': 'D:\\前端自学代码库\\webpack-vue\\05.mywebpack\\src\\count.js'
                }
             */
            //对所有依赖进行遍历
            for(const relativePath in deps){
                //依赖文件的绝对路径
                const absolutePath = deps[relativePath]
                //对依赖文件进行处理
                const fileInfo = this.build(absolutePath)
                //再将处理后的结果添加到modules容器中，后面遍历就会遍历他了
                this.modules.push(fileInfo)
            }
        })

        // console.log(this.modules);
        //将依赖关系转换成更好的依赖关系图
        /**
         * {
         *  'index.js':{
         *      code:'xxx',
         *      deps:{'add.js':'xxx'}
         *  },
         * 'add.js':{
         *      code:'xxx',
         *      deps:{}
         *  }
         * }
         */
        const depsGraph = this.modules.reduce((graph,module)=>{
            return {
                ...graph,
                [module.filePath]:{
                    code:module.code,
                    deps:module.deps
                }
            }
        },{})
        // console.log(depsGraph)
        this.generate(depsGraph)
    }
    //开始构建
    build(filePath){
        //1.将文件解析成ast
        const ast = getAst(filePath)
        //2.获取ast中所有的依赖
        const deps = getDeps(ast,filePath)
        //3.将ast解析成code
        const code = getCode(ast)
        return{
            //文件路径
            filePath,
            //当前文件中所有的依赖
            deps,
            //当前文件解析后的代码
            code
        }
    }

    //生成输出资源
    generate(depsGraph){
        const bundle = `
            (function(depsGraph){
                //require目的:为了加载入口文件
                function require(depsGraph){
                    //定义模块内部的require函数
                    function localRequire(relativePath){
                        //为了找到要引入模块的绝对路径,通过require加载
                        return require(depsGraph[module].deps[relativePath]);
                    }

                    //定义暴露对象（将来我们模块要暴露的内容）
                    var exports = {};
                    (function(require,exports,code){
                        eval(code);
                    })(localRequire,exports,depsGraph[module].code);

                    //作为require函数的返回值返回出去
                    //后面的require函数能得到暴露的内容
                    return exports;
                }
                //加载入口文件路径
                require('${this.options.entry}');
            })('${JSON.stringify(depsGraph)}')
        `
        //生成输出文件的绝对路径
        const filePath = path.resolve(this.options.output.path,this.options.output.filename)
        fs.writeFileSync(filePath,bundle,'utf-8')
    }
}

module.exports = compiler